//
//  NetworkManager.swift
//  SCA
//  Created by tjun on 2025/9/1.
//

import UIKit
import Alamofire
 
enum SCAError: Error, LocalizedError {
    case dataException
    case fileNotExist
    case timeout
    case unauthorized
    case universal(String)

    var errorDescription: String? {
         switch self {
         case .dataException:
             return "数据异常".localizedString
         case .fileNotExist:
             return "文件不存在".localizedString
         case .timeout:
             return "请求超时".localizedString
         case .unauthorized:
             return "未授权".localizedString
         case .universal(let str):
             return "通用错误: \(str)"
         }
     }

     var failureReason: String? {
         return errorDescription
     }
}

final class NetworkManager {
    
    static let shared = NetworkManager()
    private init() {}
    
    private var showErrorMessageAPIs: [String] = [
        APIEndpoint.login,
        APIEndpoint.register,
        APIEndpoint.forgetPassword,
        APIEndpoint.walletTransaction,
        APIEndpoint.setPin,
        APIEndpoint.bindAccount,
        APIEndpoint.changePassword,
        APIEndpoint.verify2FA,
        APIEndpoint.redeemPrize
    ]
    
    private var showErrorInCenterMessageAPIs: [String] = [
        APIEndpoint.register,
        APIEndpoint.login,
    ]
    
    private var notPrintLogAPIs: [String] = [

    ]
    
    private var notHiddenLoadingAPIs: [String] = [
        APIEndpoint.walletCheckUsername
    ]
    
    private func getCommonHeaders(url: String) -> HTTPHeaders {
        var commonHeader: [String: String] = [
            "Appkey": "xOTNaUI98gwYADIefrsI6By3EvFmAM1l",
            "Appid": "mac-app"
        ]
        if let token = UserInfo.token, !token.isEmpty {
            commonHeader["Authorization"] = "Bearer " + token
        }
        
        return HTTPHeaders(commonHeader)
    }
    
    private func mergeHeaders(url: String, headers: [String: String]?) -> HTTPHeaders {
        var mergedHeaders = getCommonHeaders(url: url)
        if let additionalHeaders = headers {
            for (key, value) in additionalHeaders {
                mergedHeaders.add(name: key, value: value) // 添加新的请求头
            }
        }
        
        return mergedHeaders
    }
    
    @discardableResult
    func get(
        url: String,
        parameters: [String: Any]? = nil,
        headers: [String: String]? = nil,
        success: ((_ data: Any) -> Void)? = nil,
        failure: ((_ error: Error) -> Void)? = nil
    ) -> DataRequest {
        
        let mergedHeaders = mergeHeaders(url: url, headers: headers)
        let requestUrl = getRequestUrl(url)

        return AF.request(requestUrl,
                          method: .get,
                          parameters: parameters,
                          headers: mergedHeaders, requestModifier: { request in
            request.timeoutInterval = 15
        })
        .responseData { response in
            self.handleResponse(url: url, parameters: parameters, headers: mergedHeaders, response: response, success: success, failure: failure)
        }
    }
    
    @discardableResult
    func postFormData(
        url: String,
        parameters: [String: Any]? = nil,
        headers: [String: String]? = nil,
        success: ((_ data: Any) -> Void)? = nil,
        failure: ((_ error: Error) -> Void)? = nil
    )  -> DataRequest {
        let mergedHeaders = mergeHeaders(url: url, headers: headers)
        let requestUrl = getRequestUrl(url)
        return AF.request(requestUrl,
                          method: .post,
                          parameters: parameters,
                          headers: mergedHeaders, requestModifier: { request in
            request.timeoutInterval = 15
        })
        .responseData { response in
            self.handleResponse(url: url, parameters: parameters, headers: mergedHeaders, response: response, success: success, failure: failure)
        }
    }
    
    @discardableResult
    func post(
        url: String,
        parameters: [String: Any]? = nil,
        headers: [String: String]? = nil,
        success: ((_ data: Any) -> Void)? = nil,
        failure: ((_ error: Error) -> Void)? = nil
    ) -> DataRequest {

        var requestParameters: [String: Any] = [:]
        requestParameters["l"] = LanguageManager.shared.currentLanguage.serviceLanguage
        parameters?.forEach { key, value in
            requestParameters[key] = value
        }
        
        if !requestParameters.allKeys().contains("step") {
            requestParameters["step"] = "confirm"
        }
        
        let mergedHeaders = mergeHeaders(url: url, headers: headers)
        let requestUrl = getRequestUrl(url)

        return AF.request(requestUrl,
                          method: .post,
                          parameters: requestParameters,
                          encoding: JSONEncoding.default,
                          headers: mergedHeaders, requestModifier: { request in
            request.timeoutInterval = 15
        })
        .responseData { response in
            self.handleResponse(url: url, parameters: requestParameters, headers: mergedHeaders, response: response, success: success, failure: failure)
        }
    }
    
    @discardableResult
    func delete(
        url: String,
        parameters: [String: Any]? = nil,
        headers: [String: String]? = nil,
        success: ((_ data: Any) -> Void)? = nil,
        failure: ((_ error: Error) -> Void)? = nil
    ) -> DataRequest {
        
        let mergedHeaders = mergeHeaders(url: url, headers: headers)
        let requestUrl = getRequestUrl(url)

        return AF.request(requestUrl,
                          method: .delete,
                          parameters: parameters,
                          headers: mergedHeaders, requestModifier: { request in
            request.timeoutInterval = 15
        })
        .responseData { response in
            self.handleResponse(url: url, parameters: parameters, headers: mergedHeaders, response: response, success: success, failure: failure)
        }
    }
    
    @discardableResult
    func streamRequest(
        url: String,
        parameters: [String: Any]? = nil,
        headers: [String: String]? = nil,
        success: ((_ data: [String: Any]) -> Void)? = nil,
        failure: ((_ error: Error) -> Void)? = nil,
        finish: (() -> Void)? = nil
    ) -> DataStreamRequest {
        
        var mergedHeaders = mergeHeaders(url: url, headers: headers)
        mergedHeaders.add(name: "Content-Type", value: "application/json")
        
        let requestUrl = getRequestUrl(url)
        
        return AF.streamRequest(requestUrl, method: .post, headers: mergedHeaders, requestModifier: { urlRequest in
            if let parameters = parameters {
                let jsonData = try? JSONSerialization.data(withJSONObject: parameters, options: [])
                urlRequest.httpBody = jsonData
            }
        }).validate().responseStreamString { stream in
            
            switch stream.event {
            case let .stream(result):
                if result.isSuccess, let string = result.successValue {
                    let lines = string.split(separator: "\n")
                    for line in lines {
                        if line.starts(with: "data: ") {
                            let jsonString = line.dropFirst(6)
                            if let jsonData = jsonString.data(using: .utf8), let jsonObject = jsonData.toJSON() as? [String: Any] {
                                success?(jsonObject)
                                printf(jsonObject)
//                                if let isFinish = jsonObject["isFinish"] as? Bool, isFinish == true {
//                                    finish?()
//                                }
                            }
                        }
                    }
                } else {
                    failure?(result.failureValue!)
                }
            case .complete:
                finish?()
            }
      
        }
         
    }
    
    @discardableResult
    func download(
        url: String,
        to fileURL: URL,
        headers: [String: String]? = nil,
        downloadProgress: ((_ progress: Progress) -> Void)? = nil,
        success: ((_ url: String) -> Void)? = nil,
        failure: ((_ url: String, _ error: Error) -> Void)? = nil
    ) -> DownloadRequest {

        return AF.download(url, to: { _, _ in
            return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
        }).downloadProgress { progress in
            downloadProgress?(progress)
        }
        .response { response in
            
            let requestUrl = response.request?.url?.absoluteString ?? url 
            
            if let filePath = response.fileURL?.path {
                print("下载完成，文件保存到: \(filePath)")
                success?(requestUrl)
            } else if let error = response.error {
                print("下载失败: \(error)")
                failure?(requestUrl, error)
            }
        }
    }
    
    @discardableResult
    func upload(
        url: String,
        fileData: Data,
        fileName: String,
        headers: [String: String]? = nil,
        uploadProgress: ((_ progress: Progress) -> Void)? = nil,
        success: ((_ data: Any) -> Void)? = nil,
        failure: ((_ error: Error) -> Void)? = nil
    ) -> UploadRequest {
        
        let mergedHeaders = mergeHeaders(url: url, headers: headers)
        let requestUrl = getRequestUrl(url)
        
        return AF.upload(multipartFormData: { multipartFormData in
            multipartFormData.append(fileData, withName: "file", fileName: fileName, mimeType: getMimeType(for: fileName))
        }, to: requestUrl, headers: mergedHeaders).uploadProgress { progress in
            uploadProgress?(progress)
        }.responseData { response in
            self.handleResponse(url: url, headers: mergedHeaders, response: response, success: success, failure: failure)
        }
    }
    
    @discardableResult
    func upload(
        url: String,
        fileURL: URL,
        fileName: String,
        parameters: [String: String]? = nil,
        uploadProgress: ((_ progress: Progress) -> Void)? = nil,
        success: ((_ data: Any) -> Void)? = nil,
        failure: ((_ error: Error) -> Void)? = nil
    ) -> UploadRequest {
 
        let mergedHeaders = mergeHeaders(url: url, headers: nil)
        let requestUrl = getRequestUrl(url)
        
        return AF.upload(multipartFormData: { multipartFormData in
            
            multipartFormData.append(fileURL, withName: "file", fileName: fileName, mimeType: getMimeType(for: fileName))
            parameters?.forEach { key, value in
                if let data = value.data(using: .utf8) {
                    multipartFormData.append(data, withName: key)
                }
            }
        }, to: requestUrl, headers: mergedHeaders).uploadProgress { progress in
            print("Upload Progress: \(progress.fractionCompleted)")
            uploadProgress?(progress)
        }.responseData { response in
            self.handleResponse(url: url, headers: mergedHeaders, response: response, success: success, failure: failure)
        }
    }
    
    @discardableResult
    func upload(
        url: String,
        fileData: Data,
        uploadProgress: ((_ progress: Progress) -> Void)? = nil,
        success: ((_ data: Any) -> Void)? = nil,
        failure: ((_ error: Error) -> Void)? = nil
    ) -> UploadRequest {
        
        let mergedHeaders = mergeHeaders(url: url, headers: ["Content-Type": getMimeType(for: "1.jpg")])
        return  AF.upload(
            fileData,
            to: getRequestUrl(url),
            method: .post,
            headers: mergedHeaders// 自定义方法获取 MIME 类型
        )
        .uploadProgress { progress in
            print("Upload Progress: \(progress.fractionCompleted)")
            uploadProgress?(progress)
        }
        .responseData { response in
            self.handleResponse(url: url, headers: mergedHeaders, response: response, success: success, failure: failure)
        }
    }
    
    private  func getRequestUrl(_ url: String) -> String {
        if url.hasPrefix("http") {
            return url
        }
        return getBaseUrlString() + url
    }
    
    // MARK: - Response Handler
    private func handleResponse (
        url: String,
        parameters: [String: Any]? = nil,
        headers: HTTPHeaders,
        response: AFDataResponse<Data>,
        success: ((_ data: Any) -> Void)? = nil,
        failure: ((_ error: Error) -> Void)? = nil
    ) {

        switch response.result {
        case .success(let data):
            do {
                let jsonObject = try JSONSerialization.jsonObject(with: data, options: [])
                if let json = jsonObject as? [String: Any] {
                    
                     if !notPrintLogAPIs.contains(url) {
                         printf("url = \(getRequestUrl(url)), parameters = \(String(describing: parameters)), headers = \(headers), response = \(json)")
                     }
                    
                    let errmsg = json["errmsg"] as? String
                    guard let errorCode = json["error"] as? Int,
                          let _ = json["status"] as? Int,
                          let result = json["result"] as? [String: Any] else {
                        
                        if let errMessage = errmsg, !errMessage.isBlank() {
                            if errMessage.lowercased().contains("Invalid Token".lowercased()) {
                                printf("token错误")
                                NotificationCenter.default.post(name: NotificationName.tokenError, object: nil)
                            }
                        }
                        failure?(SCAError.dataException)
                        return
                    }
                    
                    let err = result["err"] as? [String: Any]
                    if err == nil, errorCode == 0 {
                        success?(result)
                    } else {
                        let message = err?.values.first as? String
                        if let errMessage = errmsg, !errMessage.isBlank() {
                            
                            if errMessage.lowercased().contains("Invalid Token".lowercased()) {
                                printf("token错误")
                                NotificationCenter.default.post(name: NotificationName.tokenError, object: nil)
                            } else {
                                if showErrorMessageAPIs.contains(url) {
                                    HUD.showMessage(errMessage)
                                } else if showErrorInCenterMessageAPIs.contains(url) {
                                    HUD.showMessage(errMessage, offset: 0)
                                }
                                failure?(SCAError.universal(errMessage))
                            }
                        } else {
                            if showErrorMessageAPIs.contains(url) {
                                HUD.showMessage(message)
                            } else if showErrorInCenterMessageAPIs.contains(url) {
                                HUD.showMessage(message, offset: 0)
                            }
                            failure?(SCAError.universal(message ?? ""))
                        }
                    }
       
                } else {
                    let error = SCAError.dataException
                    failure?(error)
                    if !notPrintLogAPIs.contains(url) {
                        printf("url = \(getRequestUrl(url)), parameters = \(String(describing: parameters)), headers = \(headers), error =\(error)")
                    }
                }
            } catch {
                if !notPrintLogAPIs.contains(url) {
                    printf("url = \(getRequestUrl(url)), parameters = \(String(describing: parameters)), headers = \(headers), json解析失败 data =\(data)")
                    printf("data=\(String(data: data, encoding: .utf8))")
                }
                failure?(error)
            }
        case .failure(let error):
            
            failure?(error)

            if let afError = error.asAFError, afError.isSessionTaskError,
               let urlError = afError.underlyingError as? URLError {
                if urlError.code == .notConnectedToInternet || urlError.code.rawValue == -1020 {
                    HUD.showMessage("网络错误".localizedString)
                }
            }
            
            if !notPrintLogAPIs.contains(url) {
                printf("url = \(getRequestUrl(url)), parameters = \(String(describing: parameters)), headers = \(headers), error =\(error)")
            }
        }
    }
    
    func tokenError() {
        NotificationCenter.default.post(name: NotificationName.tokenError, object: nil)
    }
    
}



